package com.dzh.dzhhub.shiro.jwt;

/**
 * @author DZHooo
 * @version 1.0
 * @date 2021/11/16 23:47
 * @description: TODO
 */

import java.util.HashSet;
import java.util.Set;

import com.dzh.dzhhub.entity.User;
import com.dzh.dzhhub.service.PermissionService;
import com.dzh.dzhhub.service.UserService;
import com.dzh.dzhhub.util.JedisUtil;
import com.dzh.dzhhub.util.JwtUtils;
import com.dzh.dzhhub.util.constants.Constants;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AccountException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.tomcat.util.bcel.Const;
import org.springframework.beans.factory.annotation.Autowired;


/**
 * JwtRealm 只负责校验 JwtToken
 */
public class JwtRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    @Autowired
    private PermissionService permissionService;

    /**
     * 限定这个 Realm 只处理我们自定义的 JwtToken
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }

    /**
     * 此处的 SimpleAuthenticationInfo 可返回任意值，密码校验时不会用到它
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)
            throws AuthenticationException {
        JwtToken jwtToken = (JwtToken) authcToken;
        String token = jwtToken.getCredentials().toString();

        if (jwtToken.getPrincipal() == null) {
            throw new AccountException("JWT token参数异常！");
        }
        // 从 JwtToken 中获取当前用户
        String username = jwtToken.getPrincipal().toString();
        // 查询数据库获取用户信息，此处使用 Map 来模拟数据库
        User user = userService.getUser(username);

        // 用户不存在
        if (user == null) {
            throw new UnknownAccountException("用户不存在！");
        }

        // 开始认证，要AccessToken认证通过，且Redis中存在RefreshToken，且两个Token时间戳一致
        if(JwtUtils.verify(token,username) && JedisUtil.exists(Constants.PREFIX_SHIRO_REFRESH_TOKEN + username)) {
            //获取RefreshToken时间戳
            String currentTimeMillisRedis = JedisUtil.getObject(Constants.PREFIX_SHIRO_REFRESH_TOKEN + username).toString();
            //获取AccessToken时间戳，与RefreshToken时间戳对比
            if(JwtUtils.getClaimFiled(token, Constants.CURRENT_TIME_MILLIS).equals(currentTimeMillisRedis)) {
                return new SimpleAuthenticationInfo(token, token, getName());

            }
        }
        throw new AuthenticationException("Token已过期(Token expired or incorrect.)");
        // 用户被锁定  这个还没做
//        if (user.getLocked()) {
//            throw new LockedAccountException("该用户已被锁定,暂时无法登录！");
//        }

    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // 获取当前用户
//        User currentUser = (User) SecurityUtils.getSubject().getPrincipal();
        // UserEntity currentUser = (UserEntity) principals.getPrimaryPrincipal();

        String token = principals.toString();
        String username = JwtUtils.getClaimFiled(token,"username");
        User currentUser = userService.getUser(username);

        // 查询数据库，获取用户的角色信息
        Set<String> roles = new HashSet<>();
        roles.add(currentUser.getRoleName());
        // 查询数据库，获取用户的权限信息
        Set<String> perms = permissionService.getUserPermission(currentUser.getUserName()).getPermissionList();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setRoles(roles);
        info.setStringPermissions(perms);
        return info;
    }

}
